using System;
using System.Globalization;
using System.Threading;
using SKYPE4COMLib;

namespace Wra4Skype.Library
{
    public class ViewModel : IViewModel
    {
        private readonly SkypeClass skype;

        // provides functionality to open remote assistance to create or consume an invitation
        private readonly IRemoteAssistanceProvider remoteAssistanceProvider;

        // logger instance
        private readonly ILogger logger;

        public UserCollection Users { get; private set; }

        public InvitationMessage LastInvitation { get; private set; }

        public event EventHandler UsersLoaded;

        public event EventHandler InvitationReceived;

        // fires the UsersLoaded event
        private void InvokeUsersLoaded()
        {
            EventHandler handler = this.UsersLoaded;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        // fires the InvitationReceived event
        private void InvokeInvitationReceived()
        {
            EventHandler received = this.InvitationReceived;
            if (received != null)
            {
                received(this, EventArgs.Empty);
            }
        }

        #region Contruction

        // default constructor
        public ViewModel() : this(null, null)
        {
        }

        // constructor that accepts external interface instances - can be used for mocking them in testing
        public ViewModel(SkypeClass skype, IRemoteAssistanceProvider remoteAssistanceProvider)
        {
            // logger
            this.logger = new Logger();

            if (skype == null)
            {
                skype = new SkypeClass();
            }

            // if not provided use default classes
            if (remoteAssistanceProvider == null)
            {
                remoteAssistanceProvider = new WraProvider();
            }

            this.skype = skype;
            this.Users = this.skype.Friends;
            this.remoteAssistanceProvider = remoteAssistanceProvider;

            this.skype.MessageStatus += this.Skype_MessageStatus;
        }

        private void Skype_MessageStatus(ChatMessage message, TChatMessageStatus status)
        {
            if (status == TChatMessageStatus.cmsReceived)
            {
                // if message is invitation for remote assistance
                var invitationMessage = MessageTools.GetInvitationPartsFromMessage(message.Body);
                if (invitationMessage != null)
                {
                    message.Seen = true;
                    invitationMessage.User = message.Sender;
                    this.LastInvitation = invitationMessage;
                    this.InvokeInvitationReceived();
                }
            }
        }

        #endregion

        public void Connect()
        {
            // start a new thread that will load users
            new Thread(this.LoadUsers).Start();
        }

        private void LoadUsers()
        {
            this.InvokeUsersLoaded();
        }

        public void Disconnect()
        {
        }

        public void AcceptLastInvitation()
        {
            if (this.LastInvitation == null)
            {
                throw new InvalidOperationException("There is not invitation to start.");
            }

            // use the invitation
            this.remoteAssistanceProvider.UseInvitation(this.LastInvitation);
        }

        public void SendInvitation(string user)
        {
            // create a random password
            var password = new Random().Next(100000, 999999).ToString(CultureInfo.InvariantCulture);
            
            // create invitation
            string invitationContent = this.remoteAssistanceProvider.CreateInvitation(password);

            // send invitation
            var message = MessageTools.CreateMessageFromInvitationParts(password, invitationContent);
            this.skype.SendMessage(user, message);
        }
    }
}
